/**
 * @file bl0939.c
 * @brief bl0939(2路交流电能计量芯片)驱动
 * @author wangh (wanghuan3037@fiberhome.com)
 * @version 1.0
 * @date 2020-10-21
 * @copyright Copyright (c) 2020  烽火通信
 ***************************************************************
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version  <th>Author  <th>Description
 * <tr><td>2020-10-21 <td>1.0      <td>wangh   <td>内容
 * </table>
 */ 
#include "bl0939.h"

#if DRV_BL0939_EN
#include "project_board.h"
#include "bsp.h"

#undef LOG_LEVEL_
#define LOG_LEVEL_ 	LOG_LVL_ASSERT
#include "bsp_log.h"


#define BL_READ_TIMEOUT         100
#define BL_READ_TRYTIMES        3
#define BL_RESUME_TRYTIMES      10

static void Bl0939_Config(Bl0939_t *obj);

/**
 * @brief 计算校验和 \n
 * （(0x5,{A4,A3,A2,A1})+ADDR+Data_L+Data_M+Data_H）&0xFF 取反
 * @param  buff        数据指针
 * @param  size        数据长度
 * @return uint8_t 校验和
 */
static uint8_t Bl0939_CaclCheckSum( uint8_t *buff, uint8_t size )
{
    uint16_t checksum = 0;
    for( uint8_t i=0; i<size; i++ )
        checksum = checksum + buff[i];
    return ~(uint8_t)(checksum&0xFF);
}

// extern void hal_delay_us(uint16_t us);

/**
 * @brief Bl0939读寄存器(无锁版，中间函数)
 * @param[in]  obj      Bl0939对象
 * @param[in]  reg      寄存器地址（0xAA读数据包，34）
 * @param[in]  buffer   读取数据指针
 * @param[in]  timeout  读取超时时间（ms）
 * @param[in]  trytimes 出错重试次数
 * @return int8_t 
 * - @b Sucess : BSP_SUCCESS \n
 * - @b Fail : BSP_ERROR - 超时或校验出错
 */
static int8_t Bl0939_ReadReg_Nolock( Bl0939_t *obj, uint8_t reg, uint8_t *buffer, uint32_t timeout, uint8_t trytimes )
{
    uint8_t buff[6];

    memset(buff, 0, 6);
    buff[0] = 0x50 + obj->Addr;
    buff[1] = reg;

    do{
        vTaskDelay(1);
        UartSend( obj->UartId, buff, 2 );
        if( UartRecv( obj->UartId, &buff[2], 4, portTICK_RATE_MS*timeout ) == 4 )
        {
            if( buff[5] == Bl0939_CaclCheckSum( buff, 5 ) ) /* 比对校验和 */
            {
                memcpy(buffer, &buff[2], 3);
                obj->resume_times = 0;
                return BSP_SUCCESS;
            }
            else
                log_d( "Bl0939_CaclCheckSum err\r\n" );
        }
        else
        {
            log_d( "Bl0939_recv timeout\r\n" );
        }
    } while (trytimes--);

    log_e( "Bl0939_ReadReg timeout\r\n" );
    obj->resume_times++;
    if (obj->resume_times > BL_RESUME_TRYTIMES)
    {
        obj->resume_times = 0;
        UartReset( obj->UartId );   /* 复位串口回复 */
    }

    return BSP_ERROR;
}

/**
 * @brief Bl0939读寄存器
 * @param[in]  obj      Bl0939对象
 * @param[in]  reg      寄存器地址（0xAA读数据包，34）
 * @param[in]  buffer   读取数据指针
 * @param[in]  timeout  读取超时时间（ms）
 * @param[in]  trytimes 出错重试次数
 * @return int8_t 
 * - @b Sucess : BSP_SUCCESS \n
 * - @b Fail : BSP_ERROR - 超时或校验出错
 */
static int8_t Bl0939_ReadReg( Bl0939_t *obj, uint8_t reg, uint8_t *buffer, uint32_t timeout, uint8_t trytimes )
{
    xSemaphoreTake(obj->WR_lock, portMAX_DELAY);
    int8_t ret = Bl0939_ReadReg_Nolock( obj, reg, buffer, timeout, trytimes );
    xSemaphoreGive(obj->WR_lock);
    return ret;
}

/**
 * @brief Bl0939写寄存器（不校验、不加锁，中间函数）
 * @param[in]  obj      Bl0939对象
 * @param[in]  reg      寄存器地址
 * @param[in]  data     数据（24位）
 */
static void Bl0939_WriteReg_Nocheck( Bl0939_t *obj, uint8_t reg, uint32_t data )
{
    uint8_t buff[6];

    buff[0] = 0xA0 + obj->Addr;
    buff[1] = reg;
    buff[2] = (uint8_t)(data&0xFF);
    buff[3] = (uint8_t)((data>>8)&0xFF);
    buff[4] = (uint8_t)((data>>16)&0xFF);
    buff[5] = Bl0939_CaclCheckSum( buff, 5 );   /* 校验和 */

    UartSend( obj->UartId, buff, 6 );
}

/**
 * @brief Bl0939写寄存器（仅支持用户操作寄存器）
 * @param[in]  obj      Bl0939对象
 * @param[in]  reg      寄存器地址
 * @param[in]  data     数据（24位）
 * @param[in]  isReadCheck 是否读取验证（false：不验证，true：验证）
 * @return int8_t 
 * - @b Sucess : BSP_SUCCESS \n
 * - @b Fail : BSP_ERROR - 超时或校验出错
 */
static int8_t Bl0939_WriteReg( Bl0939_t *obj, uint8_t reg, uint32_t data, bool isReadCheck )
{
    int8_t ret = BSP_ERROR;
    uint8_t buff[6];
    uint8_t trytimes = BL_READ_TRYTIMES;

    xSemaphoreTake(obj->WR_lock, portMAX_DELAY);
    if (!isReadCheck)
    {
        Bl0939_WriteReg_Nocheck( obj, reg, data );
        ret = BSP_SUCCESS;
        goto end;
    }

    /* 读取验证 */
    do{
        Bl0939_WriteReg_Nocheck( obj, reg, data );

        memset(buff, 0, 6);
        ret = Bl0939_ReadReg_Nolock( obj, reg, buff, BL_READ_TIMEOUT, 1 );
        if (ret == BSP_SUCCESS)
        {
            if( data == (uint32_t)(((buff[2]<<16) + (buff[1]<<8) + buff[0])&0x00FFFFFF) )
            {
                ret = BSP_SUCCESS;
                obj->resume_times = 0;
                goto end;
            }
            else
            {
                log_e( "Bl0939_WriteReg check error %08X  %08X\r\n", data, (uint32_t)(((buff[2]<<16) + (buff[1]<<8) + buff[0])&0x00FFFFFF) );
                ret = BSP_ERROR_CHECK;
            }
        }
    } while (trytimes--);

    obj->resume_times++;
    if (obj->resume_times > BL_RESUME_TRYTIMES)
    {
        obj->resume_times = 0;
        UartReset( obj->UartId );   /* 复位串口回复 */
    }

end:
    xSemaphoreGive(obj->WR_lock);
    return ret;
}

/**
 * @brief 读无符号寄存器
 * @param[in]  obj      Bl0939对象
 * @param[in]  reg      寄存器地址
 * @param[out] value    寄存器值
 * @return int8_t 
 * - @b Sucess : BSP_SUCCESS \n
 * - @b Fail : @ref Bl0939_ReadReg
 */
static int8_t Bl0939_ReadRegUint( Bl0939_t *obj, uint8_t reg, uint32_t *value )
{
    uint8_t buff[3];
    memset(buff, 0, 3);

    int8_t ret = Bl0939_ReadReg( obj, reg, buff, BL_READ_TIMEOUT, BL_READ_TRYTIMES );
    if(ret != BSP_SUCCESS)
    {
        log_e( "Bl0939_ReadReg error(%d)\r\n", ret );
        return ret;
    }
    log_v("Bl0939_ReadReg %02X %02X %02X\r\n", buff[0], buff[1], buff[2]);

    *value = (uint32_t)(((buff[2]<<16) + (buff[1]<<8) + buff[0])&0x00FFFFFF);

    return BSP_SUCCESS;
}

/**
 * @brief 读有符号寄存器
 * @param[in]  obj      Bl0939对象
 * @param[in]  reg      寄存器地址
 * @param[out] value    寄存器值
 * @return int8_t 
 * - @b Sucess : BSP_SUCCESS \n
 * - @b Fail : @ref Bl0939_ReadReg
 */
static int8_t Bl0939_ReadRegInt( Bl0939_t *obj, uint8_t reg, int32_t *value )
{
    uint32_t utemp;

    int8_t ret = Bl0939_ReadRegUint( obj, reg, &utemp );
    if (ret != BSP_SUCCESS)
        return ret;

    int32_t itemp = (int32_t)utemp;
    if( ( itemp&0x800000 ) == 0x800000 )
        itemp |= 0xff000000; /* 高位补1 */

    *value = itemp;

    return BSP_SUCCESS;
}

/**
 * @brief 电量统计超时处理函数
 */
static void blTimer_timeout_ind(TimerHandle_t xTimer)
{
    Bl0939_t *obj = (Bl0939_t * )pvTimerGetTimerID(xTimer);
    uint32_t utempA = 0;
    uint32_t utempB = 0;

    uint32_t utemp = 0;
    Bl0939_ReadRegUint( obj, Addr_USR_MODE, &utemp );
    log_v("Addr_USR_MODE = %08X\r\n", utemp);
#if BL0939_CF_CLR_SEL
    if (utemp != 0x1400)
#else
    if (utemp != 0x1000)
#endif
    {
        Bl0939_Config(obj);
        log_e( "Bl0939 reconfig...\r\n" );
    }

#if BL0939_CFA_EN
    if (BSP_SUCCESS != Bl0939_ReadRegUint( obj, Addr_CFA_CNT, &utempA ))
        return;
    #if BL0939_CF_CLR_SEL
    if (utempA/obj->Energy_K > 10)  /* 异常数值排除 */
        return;
    #endif
#endif

#if BL0939_CFB_EN
    if (BSP_SUCCESS != Bl0939_ReadRegUint( obj, Addr_CFB_CNT, &utempB ))
        return;
    #if BL0939_CF_CLR_SEL
    if (utempB/obj->Energy_K > 10)  /* 异常数值排除 */
        return;
    #endif
    log_v("Addr_CFB_CNT = %d\r\n", utempB);
#endif


#if BL0939_CF_CLR_SEL   /* CF自动清零 */
#if BL0939_ENERGY_USE_FLOAT
    xSemaphoreTake(obj->Energy_lock, portMAX_DELAY);
    #if BL0939_CFA_EN
    obj->Energy.Energy_A = obj->Energy.Energy_A + (float)utempA/obj->Energy_K;
    #endif
    #if BL0939_CFB_EN
    obj->Energy.Energy_B = obj->Energy.Energy_B + (float)utempB/obj->Energy_K;
    #endif
    xSemaphoreGive(obj->Energy_lock);
#else
    #if BL0939_CFA_EN
    utempA = utempA*1000 + obj->EnergyMid.EnergyMid_A;
    obj->EnergyMid.EnergyMid_A = utempA % obj->Energy_K;
    #endif
    #if BL0939_CFB_EN
    utempB = utempB*1000 + obj->EnergyMid.EnergyMid_B;
    obj->EnergyMid.EnergyMid_B = utempB % obj->Energy_K;
    #endif
    xSemaphoreTake(obj->Energy_lock, portMAX_DELAY);
    #if BL0939_CFA_EN
    obj->Energy.Energy_A = obj->Energy.Energy_A + utempA/obj->Energy_K;
    #endif
    #if BL0939_CFB_EN
    obj->Energy.Energy_B = obj->Energy.Energy_B + utempB/obj->Energy_K;
    #endif
    xSemaphoreGive(obj->Energy_lock);
#endif

#else   /* CF不清零 */
#if BL0939_ENERGY_USE_FLOAT
    xSemaphoreTake(obj->Energy_lock, portMAX_DELAY);
    #if BL0939_CFA_EN
    obj->Energy.Energy_A = obj->EnergyMid.EnergyMid_A + (float)utempA/obj->Energy_K;
    #endif
    #if BL0939_CFB_EN
    obj->Energy.Energy_B = obj->EnergyMid.EnergyMid_B + (float)utempB/obj->Energy_K;
    #endif
    xSemaphoreGive(obj->Energy_lock);
#else
    xSemaphoreTake(obj->Energy_lock, portMAX_DELAY);
    #if BL0939_CFA_EN
    obj->Energy.Energy_A = obj->EnergyMid.EnergyMid_A + utempA*1000/obj->Energy_K;
    #endif
    #if BL0939_CFB_EN
    obj->Energy.Energy_B = obj->EnergyMid.EnergyMid_B + utempB*1000/obj->Energy_K;
    #endif
    xSemaphoreGive(obj->Energy_lock);
#endif

    if ((utempA > 0x7FFFFF) || (utempB > 0x7FFFFF)) /* 超限清零 */
    {
        #if BL0939_CFA_EN
        obj->EnergyMid.EnergyMid_A = obj->Energy.Energy_A;
        #endif
        #if BL0939_CFB_EN
        obj->EnergyMid.EnergyMid_B = obj->Energy.Energy_B;
        #endif
        Bl0939_WriteReg( obj, Addr_USR_WRPROT, 0x55, false );
        Bl0939_WriteReg( obj, Addr_SOFT_RESET, 0x5A5A5A, false );
        Bl0939_Config( obj );
    }
#endif
}

static void Bl0939_Config(Bl0939_t *obj)
{
    /* 开用户写保护 */
    if( BSP_SUCCESS != Bl0939_WriteReg( obj, Addr_USR_WRPROT, 0x55, true ) )
    {
        log_e( "Bl0939_WriteReg Addr_USR_WRPROT fail\r\n" );
        return;
    }

    /* 防潜动阈值设置，有功功率设置4W以下切除到零;阈值大小根据实际情况设置 */
    if( BSP_SUCCESS != Bl0939_WriteReg( obj, Addr_WA_CREEP, (uint32_t)(obj->Power_K/6), true ) )  /* WA_CREEP = WATT/3.0517578125/8 */
        return;

    Bl0939_WriteReg( obj, Addr_TPS_CTRL, 0x47FF, false );

    /* 电压、电流A/B有效值/快速有效值过高通， 有效值更新速度400ms，交流电频率50Hz，CF计数寄存器读后清零，CF引脚报警输出 */
#if BL0939_CF_CLR_SEL
    Bl0939_WriteReg( obj, Addr_USR_MODE, 0x1400, true );
#else
    Bl0939_WriteReg( obj, Addr_USR_MODE, 0x1000, true );   /* CF不自动清零 */
#endif
}

/**
 * @brief Bl0939初始化
 * @param[in]  obj      Bl0939对象
 * @param[in]  uartId   串口外设编号
 * @param[in]  tx       串口TX引脚
 * @param[in]  rx       串口RX引脚
 * @param[in]  cf       CF引脚
 * @param[in]  addr     器件地址
 * @return int8_t 
 * - @b Sucess : BSP_SUCCESS \n
 * - @b Fail
 * - @ref BSP_ERROR_INVALID_PARAM - 非法入参
 * - @ref BSP_ERROR_ALREADY_INIT - 已初始化
 * - @ref BSP_ERROR - 初始化出错
 * - @ref BSP_ERROR_NO_MEM - 内存出错
 */
int8_t Bl0939_Init( Bl0939_t *obj, UartId_t uartId, PinNames tx, PinNames rx, PinNames cf, uint8_t addr )
{
    if (obj == NULL)
        return BSP_ERROR_INVALID_PARAM;

    if( obj->IsInitialized )
    {
        log_e( "Bl0939_Init error: has already Initialized\r\n" );
        return BSP_ERROR_ALREADY_INIT;
    }

    obj->UartId = uartId;
    obj->Addr = addr;
    if(BSP_SUCCESS != UartInit( uartId, tx, rx, 64 ))
        return BSP_ERROR;
    UartConfig( uartId, RX_TX, 4800, UART_8_BIT, UART_1_5_STOP_BIT, NO_PARITY, NO_FLOW_CTRL );

    // GpioInit( &obj->CF, cf, PIN_INPUT, PIN_PUSH_PULL, PIN_PULL_DOWN, 2 );   /* A通道漏电/过流报警输出指示引脚,告警时拉高 */
    // GpioSetInterrupt( &obj->CF, IRQ_RISING_EDGE, IRQ_HIGH_PRIORITY, GpioIrqHandler *irqHandler );

    /* 电参数计算系数设置 */
#if BL0939_ELECT_USE_FLOAT
    obj->Current_K = 452222.33;     /* 324004*1.7/1.218 = 452222.33 */
    obj->L_Current_K = 886710.454;  /* 324004*(10/3)/1.218 = 886710.454 */
    obj->Voltage_K = 13480.043;     /* 79931*(41/(49.9*4))/1.218 = 13480.043 */
    obj->Power_K = 952.365;         /* 4046*(41/(49.9*4))*1.7/(1.218*1.218) = 952.365 */
#else
    obj->Current_K = 452222;
    obj->L_Current_K = 886710;
    obj->Voltage_K = 13480;
    obj->Power_K = 952;
#endif

#if BL0939_ENERGY_USE_FLOAT
    obj->Energy_K = 8174.216;       /* 3600000*Power_K/1638.4/256 = 8174.216 */
#else
    obj->Energy_K = 8174;
#endif

    /* 电量统计清零 */
    memset( &obj->Energy, 0, sizeof(Bl0939_Energy_t) );
#if !(BL0939_ENERGY_USE_FLOAT && BL0939_CF_CLR_SEL)
    memset( &obj->EnergyMid, 0, sizeof(Bl0939_EnergyMid_t) );
#endif

    /* RS485通信锁 */
    obj->WR_lock = xSemaphoreCreateBinary();    /* 初始时信号值为0 */
    if(obj->WR_lock == NULL)
    {
        log_e("bl0939 WR_lock create error\r\n");
        return BSP_ERROR_NO_MEM;
    }
    xSemaphoreGive(obj->WR_lock);

    /* 开用户写保护 */
    if( BSP_SUCCESS != Bl0939_WriteReg( obj, Addr_USR_WRPROT, 0x55, true ) )
    {
        log_e( "Bl0939_WriteReg Addr_USR_WRPROT fail\r\n" );
        return BSP_ERROR;
    }
    vTaskDelay(1);

    Bl0939_WriteReg( obj, Addr_SOFT_RESET, 0x5A5A5A, false );
    Bl0939_WriteReg( obj, Addr_USR_WRPROT, 0x55, false );

    /* 电压、电流A/B有效值/快速有效值过高通， 有效值更新速度400ms，交流电频率50Hz，CF计数寄存器读后清零，CF引脚报警输出 */
#if BL0939_CF_CLR_SEL
    Bl0939_WriteReg( obj, Addr_USR_MODE, 0x1400, true );
#else
    Bl0939_WriteReg( obj, Addr_USR_MODE, 0x1000, false );   /* CF不自动清零 */
#endif

    /* 测温开100ms，电流 A 通道过流/漏电报警开启 */
    Bl0939_WriteReg( obj, Addr_TPS_CTRL, 0x47FF, false );

    /* 防潜动阈值设置，有功功率设置4W以下切除到零;阈值大小根据实际情况设置 */
    Bl0939_WriteReg( obj, Addr_WA_CREEP, (uint32_t)(obj->Power_K/6), false );  /* WA_CREEP = WATT/3.0517578125/8 */

    /* 关闭写保护 */
    Bl0939_WriteReg( obj, Addr_USR_WRPROT, 0x00, false );


    /* 电量统计读写锁 */
    obj->Energy_lock = xSemaphoreCreateBinary();
    if(obj->Energy_lock == NULL)
    {
        log_e("bl0939 Energy_lock create error\r\n");
        return BSP_ERROR_NO_MEM;
    }
    xSemaphoreGive(obj->Energy_lock);

    /* 电量统计定时器 */
    obj->bl_timer = xTimerCreate("bl0939", BL0939_ENERGY_PERIOD * portTICK_RATE_MS, pdTRUE, obj, blTimer_timeout_ind);
    if(obj->bl_timer == NULL)
    {
        log_e("bl0939 bl_timer create error\r\n");
        return BSP_ERROR_NO_MEM;
    }
    xTimerStart( obj->bl_timer, 0 );

    obj->IsInitialized = true;

    return BSP_SUCCESS;
}

/**
 * @brief Bl0939去初始化
 * @param[in]  obj      Bl0939对象
 */
void Bl0939_DeInit( Bl0939_t *obj )
{
    if (obj == NULL)
        return;

    obj->IsInitialized = false;
    UartDeInit( obj->UartId );
    // GpioInit( &obj->CF, obj->CF.pin, PIN_INPUT, PIN_PUSH_PULL, PIN_NO_PULL, 2 );
    // GpioRemoveInterrupt( &obj->CF );

    if (obj->WR_lock)
        vSemaphoreDelete( obj->WR_lock );
    if (obj->Energy_lock)
        vSemaphoreDelete( obj->Energy_lock );
    if (obj->bl_timer)
        xTimerDelete( obj->bl_timer, 0 );
}

/**
 * @brief Bl0939设置电量值
 * @param[in]  obj      Bl0939对象
 * @param[in]  Energy   设置的电量信息结构体
 * @return int8_t 
 * - @b Sucess : BSP_SUCCESS \n
 * - @b Fail
 * - @ref BSP_ERROR_INVALID_PARAM - 非法入参
 * - @ref BSP_ERROR_NO_INIT - 未初始化
 */
int8_t Bl0939_SetEnergy( Bl0939_t *obj, Bl0939_Energy_t *Energy )
{
    if ((obj == NULL) || (Energy == NULL))
        return BSP_ERROR_INVALID_PARAM;
    
    if ( !obj->IsInitialized )
        return BSP_ERROR_NO_INIT;

    xSemaphoreTake(obj->Energy_lock, portMAX_DELAY);
    memcpy( &obj->Energy, Energy, sizeof(Bl0939_Energy_t) );
#if !(BL0939_ENERGY_USE_FLOAT && BL0939_CF_CLR_SEL)
    memset( &obj->EnergyMid, 0, sizeof(Bl0939_EnergyMid_t) );
#endif
    xSemaphoreGive(obj->Energy_lock);

#if !BL0939_CF_CLR_SEL
    Bl0939_WriteReg( obj, Addr_USR_WRPROT, 0x55, false );
    Bl0939_WriteReg( obj, Addr_SOFT_RESET, 0x5A5A5A, false );
    Bl0939_Config( obj );
#endif

    return BSP_SUCCESS;
}

/**
 * @brief Bl0939获取电量值
 * @param[in]  obj      Bl0939对象
 * @param[in]  Energy   统计的电量信息结构体
 * @return int8_t 
 * - @b Sucess : BSP_SUCCESS \n
 * - @b Fail
 * - @ref BSP_ERROR_INVALID_PARAM - 非法入参
 * - @ref BSP_ERROR_NO_INIT - 未初始化
 */
int8_t Bl0939_GetEnergy( Bl0939_t *obj, Bl0939_Energy_t *Energy )
{
    if ((obj == NULL) || (Energy == NULL))
        return BSP_ERROR_INVALID_PARAM;

    if( !obj->IsInitialized )
        return BSP_ERROR_NO_INIT;

    xSemaphoreTake(obj->Energy_lock, portMAX_DELAY);
    memcpy( Energy, &obj->Energy, sizeof(Bl0939_Energy_t) );
    xSemaphoreGive(obj->Energy_lock);

    return BSP_SUCCESS;
}

/**
 * @brief 获取电量瞬时参数
 * @param[in]  obj      Bl0939对象
 * @param[in]  Elect    电参数信息
 * @param[in]  mask     电参数选项掩码
 * @return int8_t 
 * - @b Sucess :  \n
 * - @b Fail
 * - @ref BSP_ERROR_INVALID_PARAM - 非法入参
 * - @ref BSP_ERROR_NO_INIT - 未初始化
 * - 其他寄存器读取错误
 * @par 示例:
 * @code
 *    Bl0939_GetElect( obj, Elect, BL0939_ELECT_P_ALL );
 *    Bl0939_GetElect( obj, Elect, BL0939_ELECT_I_A | BL0939_ELECT_L_B );
 * @endcode
 */
int8_t Bl0939_GetElect( Bl0939_t *obj, Bl0939_Elect_t *Elect, uint8_t mask )
{
    uint32_t utemp;
    int32_t itemp;
    int8_t ret;

    if ((obj == NULL) || (Elect == NULL) || (mask == 0))
        return BSP_ERROR_INVALID_PARAM;

    if (!obj->IsInitialized)
    {
        log_e( "Bl0939 no Initialized\r\n" );
        return BSP_ERROR_NO_INIT;
    }

#if BL0939_A_WATT_EN
    if (mask & BL0939_ELECT_P_A)    /* A通道有功功率 unit: 0.1W */
    {
        ret = Bl0939_ReadRegInt( obj, Addr_A_WATT, &itemp );
        if (ret != BSP_SUCCESS)
            goto error_handle;

        log_v("Addr_A_WATT = %d\r\n", itemp);
#if BL0939_ELECT_USE_FLOAT
        Elect->Power_Value_A = (float)abs(itemp)/obj->Power_K;
        log_v("Power_Value_A = %.3f\r\n", Elect->Power_Value_A);
#else
        Elect->Power_Value_A = abs(itemp)*10/obj->Power_K;
        log_v("Power_Value_A = %d\r\n", Elect->Power_Value_A);
#endif
    }
#endif

#if BL0939_B_WATT_EN
    if (mask & BL0939_ELECT_P_B)    /* B通道有功功率 unit: 0.1W */
    {
        ret = Bl0939_ReadRegInt( obj, Addr_B_WATT, &itemp );
        if (ret != BSP_SUCCESS)
            goto error_handle;

        log_v("Addr_B_WATT = %d\r\n", itemp);
#if BL0939_ELECT_USE_FLOAT
        Elect->Power_Value_B = (float)abs(itemp)/obj->Power_K;
        log_v("Power_Value_B = %.3f\r\n", Elect->Power_Value_B);
#else
        Elect->Power_Value_B = abs(itemp)*10/obj->Power_K;
        log_v("Power_Value_B = %d\r\n", Elect->Power_Value_B);
#endif
    }
#endif

#if BL0939_IA_RMS_EN
    if (mask & BL0939_ELECT_I_A)    /* A通道电流有效值 0.001A */
    {
        ret = Bl0939_ReadRegUint( obj, Addr_IA_RMS, &utemp );
        if (ret != BSP_SUCCESS)
            goto error_handle;

        log_v("Addr_IA_RMS = %d\r\n", utemp);
#if BL0939_ELECT_USE_FLOAT
        Elect->Current_Value_A = (float)utemp/obj->Current_K;
        log_v("Current_Value_A = %.3f\r\n", Elect->Current_Value_A);
#else
        Elect->Current_Value_A = utemp*1000/obj->Current_K;
        log_v("Current_Value_A = %d\r\n", Elect->Current_Value_A);
#endif
#if (BL0939_RMS_CREEP_VALUE > 0)
        #if BL0939_ELECT_USE_FLOAT
        Elect->Current_Value_A = (Elect->Current_Value_A < (float)BL0939_RMS_CREEP_VALUE/1000) ? 0 : Elect->Current_Value_A;
        #else
        Elect->Current_Value_A = (Elect->Current_Value_A < BL0939_RMS_CREEP_VALUE) ? 0 : Elect->Current_Value_A;
        #endif
#endif
    }
#endif

#if BL0939_IB_RMS_EN
    if (mask & BL0939_ELECT_I_B)    /* B通道电流有效值 0.001A */
    {
        ret = Bl0939_ReadRegUint( obj, Addr_IB_RMS, &utemp );
        if (ret != BSP_SUCCESS)
            goto error_handle;

        log_v("Addr_IB_RMS = %d\r\n", utemp);
#if BL0939_ELECT_USE_FLOAT
        Elect->Current_Value_B = (float)utemp/obj->Current_K;
        log_v("Current_Value_B = %.3f\r\n", Elect->Current_Value_B);
#else
        Elect->Current_Value_B = utemp*1000/obj->Current_K;
        log_v("Current_Value_B = %d\r\n", Elect->Current_Value_B);
#endif
#if (BL0939_RMS_CREEP_VALUE > 0)
        #if BL0939_ELECT_USE_FLOAT
        Elect->Current_Value_B = (Elect->Current_Value_B < (float)BL0939_RMS_CREEP_VALUE/1000) ? 0 : Elect->Current_Value_B;
        #else
        Elect->Current_Value_B = (Elect->Current_Value_B < BL0939_RMS_CREEP_VALUE) ? 0 : Elect->Current_Value_B;
        #endif
#endif
    }
#endif

#if BL0939_V_RMS_EN
    if (mask & BL0939_ELECT_V)      /* 电压有效值 0.1V */
    {
        ret = Bl0939_ReadRegUint( obj, Addr_V_RMS, &utemp );
        if (ret != BSP_SUCCESS)
            goto error_handle;

        log_v("Addr_V_RMS = %d\r\n", utemp);
#if BL0939_ELECT_USE_FLOAT
        Elect->Voltage_Value = (float)utemp/obj->Voltage_K;
        log_v("Voltage_Value = %.3f\r\n", Elect->Voltage_Value);
#else
        Elect->Voltage_Value = utemp*10/obj->Voltage_K;
        log_v("Voltage_Value = %d\r\n", Elect->Voltage_Value);
#endif
    }
#endif

#if BL0939_IA_FAST_RMS_EN
    if (mask & BL0939_ELECT_L_A)    /* A通道快速有效值（漏电流） 0.001A */
    {
        ret = Bl0939_ReadRegUint( obj, Addr_IA_FAST_RMS, &utemp );
        if (ret != BSP_SUCCESS)
            goto error_handle;

        log_v("Addr_IA_FAST_RMS = %d\r\n", utemp);
#if BL0939_ELECT_USE_FLOAT
        Elect->LeakCur_Value_A = (float)utemp/obj->L_Current_K;
        log_v("LeakCur_Value_A = %.3f\r\n", Elect->LeakCur_Value_A);
#else
        Elect->LeakCur_Value_A = utemp*1000/obj->L_Current_K;
        log_v("LeakCur_Value_A = %d\r\n", Elect->LeakCur_Value_A);
#endif
#if (BL0939_FAST_RMS_CREEP_VALUE > 0)
        #if BL0939_ELECT_USE_FLOAT
        Elect->LeakCur_Value_A = (Elect->LeakCur_Value_A < (float)BL0939_FAST_RMS_CREEP_VALUE/1000) ? 0 : Elect->LeakCur_Value_A;
        #else
        Elect->LeakCur_Value_A = (Elect->LeakCur_Value_A < BL0939_FAST_RMS_CREEP_VALUE) ? 0 : Elect->LeakCur_Value_A;
        #endif
#endif
    }
#endif

#if BL0939_IB_FAST_RMS_EN
    if (mask & BL0939_ELECT_L_B)    /* B通道快速有效值（漏电流） 0.001A */
    {
        ret = Bl0939_ReadRegUint( obj, Addr_IB_FAST_RMS, &utemp );
        if (ret != BSP_SUCCESS)
            goto error_handle;

        log_v("Addr_IB_FAST_RMS = %d\r\n", utemp);
#if BL0939_ELECT_USE_FLOAT
        Elect->LeakCur_Value_B = (float)utemp/obj->L_Current_K;
        log_v("LeakCur_Value_B = %.3f\r\n", Elect->LeakCur_Value_B);
#else
        Elect->LeakCur_Value_B = utemp*1000/obj->L_Current_K;
        log_v("LeakCur_Value_B = %d\r\n", Elect->LeakCur_Value_B);
#endif
#if (BL0939_FAST_RMS_CREEP_VALUE > 0)
        #if BL0939_ELECT_USE_FLOAT
        Elect->LeakCur_Value_B = (Elect->LeakCur_Value_B < (float)BL0939_FAST_RMS_CREEP_VALUE/1000) ? 0 : Elect->LeakCur_Value_B;
        #else
        Elect->LeakCur_Value_B = (Elect->LeakCur_Value_B < BL0939_FAST_RMS_CREEP_VALUE) ? 0 : Elect->LeakCur_Value_B;
        #endif
#endif
    }
#endif

#if BL0939_TPS1_EN
    if (mask & BL0939_ELECT_TPS)    /* 内部温度 0.1℃ */
    {
        ret = Bl0939_ReadRegUint( obj, Addr_TPS1, &utemp );
        if (ret != BSP_SUCCESS)
            goto error_handle;

#if BL0939_ELECT_USE_FLOAT
        Elect->TPS1 = (float)((float)((utemp*5-320)*170)/480-450);
#else
        Elect->TPS1 = (((utemp*5-320)*170)/480-450);
#endif
    }
#endif

    return BSP_SUCCESS;

error_handle:
    log_e( "Bl0939_ReadReg error(%d)\r\n", ret );
    return ret;
}


#endif  /* BL0939_EN */

/*********** (C) COPYRIGHT 2020 FiberHome *****END OF FILE****/
